package utils.map;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 具有期限限制的Map.
 * 
 * @param <K>
 *            '键'类型
 * @param <V>
 *            '值'类型
 * @param <T>
 *            '限制'类型
 * @author zhangbo
 * @since 1.0.0
 */
public abstract class LimitedMap<K, V> implements Map<K, V> {

    private static Logger log = LoggerFactory.getLogger(LimitedMap.class);
    public Map<K, V> dataMap;

    public Map<K, Limit> conditionMap;

    public Limit defaultLimitKey;

    @Override
    public int size() {
        removeIfExired();
        return dataMap.size();
    }

    @Override
    public boolean isEmpty() {
        removeIfExired();
        return dataMap.isEmpty();
    }

    @Override
    public boolean containsKey(Object key) {
        removeIfExired();
        return dataMap.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value) {
        removeIfExired();
        return dataMap.containsValue(value);
    }

    @Override
    public V get(Object key) {
        removeIfExired();
        Limit condition = conditionMap.get(key);
        if (condition != null) {
            condition.use();
            return dataMap.get(key);
        } else {
            dataMap.remove(key);
            return null;
        }
    }

    /**
     * will use default limit key.
     *
     * @param key
     *            key
     * @param value
     *            value
     * @return the previous value associated with key, or null if there was no
     *         mapping for key. (A null return can also indicate that the map
     *         previously associated null with key, if the implementation
     *         supports null values.)
     * 
     * @throws IllegalArgumentException
     *             if limit key is null, will throw
     *             {@link java.lang.IllegalArgumentException#IllegalArgumentException}
     * @see java.util.Map#put(java.lang.Object, java.lang.Object).
     * @author zhangbo
     * @since 1.0.0
     */
    @Override
    public V put(K key, V value) {
        if (defaultLimitKey == null) {
            throw new IllegalArgumentException("未初始化限制条件");
        }
        removeIfExired();
        defaultLimitKey.renew();
        conditionMap.put(key, defaultLimitKey.copy());
        return dataMap.put(key, value);
    }

    @Override
    public V remove(Object key) {
        removeIfExired();
        return dataMap.remove(key);
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        removeIfExired();
        for (Entry<? extends K, ? extends V> entrySet : m.entrySet()) {
            defaultLimitKey.renew();
            conditionMap.put(entrySet.getKey(), defaultLimitKey.copy());
            dataMap.put(entrySet.getKey(), entrySet.getValue());
        }
    }

    @Override
    public void clear() {
        checkIfNull();
        dataMap.clear();
        conditionMap.clear();
        defaultLimitKey.expire();
    }

    @Override
    public Set<K> keySet() {
        removeIfExired();
        return dataMap.keySet();
    }

    @Override
    public Collection<V> values() {
        removeIfExired();
        return dataMap.values();
    }

    @Override
    public Set<Entry<K, V>> entrySet() {
        removeIfExired();
        return dataMap.entrySet();
    }

    /**
     * 如果数据已经过期，则清除.
     *
     * @author zhangbo
     * @since 1.0.0
     */
    public void removeIfExired() {
        checkIfNull();
        for (Entry<K, V> entry : dataMap.entrySet()) {
            removeIfExired(entry.getKey());
        }
    }

    /**
     * 如果key对应数据已经过期，则删除dataMap中的key对应的数据.
     *
     * @param key
     *            K
     * @author zhangbo
     * @since 1.0.0
     */
    public void removeIfExired(K key) {
        if (checkIfNull()) {
            return;
        }
        Limit exiredCondition = conditionMap.get(key);
        if (exiredCondition != null) {
            if (exiredCondition.isExpired()) {
                dataMap.remove(key);
            }
        } else {
            dataMap.remove(key);
        }
    }

    public V put(K key, V value, Limit limit) {
        if (limit == null) {
            return put(key, value);
        }
        checkIfNull();
        if (limit.isExpired()) {
            log.warn("放入的数据已经过期");
            return null;
        }
        removeIfExired();
        conditionMap.put(key, limit.copy());
        return dataMap.put(key, value);
    }

    // 内部使用的map数据是否为null
    private boolean checkIfNull() {
        if (conditionMap == null || dataMap == null) {
            throw new IllegalArgumentException("未初始化期限限制MAP");
        } else {
            return false;
        }
    }
}
